package handler

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"

	"dns-tools/pkg/dns"
	"dns-tools/pkg/utils"
	"dns-tools/pkg/validator"
	"dns-tools/pkg/verify"

	"github.com/sirupsen/logrus"
)

// Response 标准响应格式
// 统一约定：
// - 成功（HTTP 200）：code=1，data 携带有效数据；适用于“验证全部成功”或“查询结果非空”。
// - 失败（HTTP 非 200）：code=0，msg 为错误汇总；必要时使用 errors 携带详细项数组/对象，便于前端逐项展示。
type Response struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg,omitempty"`
	Data interface{} `json:"data,omitempty"`
	// Errors 统一为数组或对象，类型灵活以便不同接口携带详细错误
	Errors interface{} `json:"errors,omitempty"`
}

// Handlers 所有处理器集合
type Handlers struct {
	logger        *logrus.Logger
	dnsResolver   dns.Resolver                // 通用 DNS 解析器接口
	caaVerifier   verify.CAAVerifierInterface // 通用 CAA 验证器接口
	linkVerifier  *utils.LinkVerifier
	whoisClient   *utils.WhoisClient
	batchVerifier *verify.BatchVerifier
	dnsServers    []string                    // 实际使用的 DNS 服务器（用于响应）
}

// NewHandlers 创建处理器集合
// dnsConfig: DNS 配置（provider 名称或 "primary,secondary"）
func NewHandlers(logger *logrus.Logger, dnsConfig string) *Handlers {
	// 创建 DNS 解析器（根据配置）
	resolver := createDNSResolver(dnsConfig, logger)

	// 获取实际使用的 DNS 服务器地址
	var dnsServers []string
	if googleResolver, ok := resolver.(*dns.GoogleDNSResolver); ok {
		primary, secondary := googleResolver.GetServers()
		dnsServers = []string{primary, secondary}
	} else {
		// 默认值（向后兼容）
		dnsServers = []string{"8.8.8.8:53", "8.8.4.4:53"}
	}

	return &Handlers{
		logger:        logger,
		dnsResolver:   resolver,
		caaVerifier:   verify.NewCAAVerifier(resolver),
		linkVerifier:  utils.NewLinkVerifier(), // 默认安全模式（严格 TLS + 跟随重定向）
		whoisClient:   utils.NewWhoisClient(nil),
		batchVerifier: verify.NewBatchVerifier(
			verify.WithMaxConcurrency(20),
			verify.WithTimeout(10*time.Second),
		),
		dnsServers: dnsServers,
	}
}

// createDNSResolver 根据配置创建 DNS 解析器
func createDNSResolver(config string, logger *logrus.Logger) dns.Resolver {
	config = strings.TrimSpace(config)

	// 如果为空，使用默认（Google Public DNS）
	if config == "" {
		logger.Info("Using default DNS provider: Google Public DNS (8.8.8.8/8.8.4.4)")
		return dns.NewGoogleDNSResolver()
	}

	// 尝试解析为 provider 名称
	switch strings.ToLower(config) {
	case "google":
		logger.Info("Using DNS provider: Google Public DNS (8.8.8.8/8.8.4.4)")
		return dns.NewDNSResolverWithProvider(dns.ProviderGoogle)
	case "cloudflare":
		logger.Info("Using DNS provider: Cloudflare DNS (1.1.1.1/1.0.0.1)")
		return dns.NewDNSResolverWithProvider(dns.ProviderCloudflare)
	case "alidns", "ali":
		logger.Info("Using DNS provider: AliDNS (223.5.5.5/223.6.6.6)")
		return dns.NewDNSResolverWithProvider(dns.ProviderAliDNS)
	case "dnspod", "tencent":
		logger.Info("Using DNS provider: DNSPod (119.29.29.29/182.254.116.116)")
		return dns.NewDNSResolverWithProvider(dns.ProviderDNSPod)
	case "quad9":
		logger.Info("Using DNS provider: Quad9 (9.9.9.9/149.112.112.112)")
		return dns.NewDNSResolverWithProvider(dns.ProviderQuad9)
	}

	// 尝试解析为 "primary,secondary" 格式
	if strings.Contains(config, ",") {
		parts := strings.Split(config, ",")
		if len(parts) == 2 {
			primary := strings.TrimSpace(parts[0])
			secondary := strings.TrimSpace(parts[1])
			logger.WithFields(logrus.Fields{
				"primary":   primary,
				"secondary": secondary,
			}).Info("Using custom DNS servers")
			return dns.NewDNSResolver(primary, secondary)
		}
	}

	// 尝试解析为单个 IP（使用相同的主备）
	if net.ParseIP(config) != nil || strings.Contains(config, ":") {
		logger.WithField("server", config).Info("Using custom DNS server (same for primary and secondary)")
		return dns.NewDNSResolver(config, config)
	}

	// 无法解析，使用默认
	logger.WithField("config", config).Warn("Invalid DNS config, using default Google Public DNS")
	return dns.NewGoogleDNSResolver()
}

// DNSQueryHandler DNS查询处理器
func (h *Handlers) DNSQueryHandler(w http.ResponseWriter, r *http.Request) {
	// 兼容旧版 nslookup.php：支持表单 host/type 或 JSON domain/type
	if r.Method != http.MethodPost {
		h.sendError(w, http.StatusMethodNotAllowed, "仅支持 POST 请求")
		return
	}

	// 限制请求体大小至 200KB
	r.Body = http.MaxBytesReader(w, r.Body, 200*1024)

	var req struct {
		Domain string `json:"domain"`
		Type   string `json:"type"`
	}

	// 根据 Content-Type 判断解析方式
	ct := r.Header.Get("Content-Type")
	if strings.HasPrefix(ct, "application/json") {
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			h.sendError(w, http.StatusBadRequest, "请求格式无效")
			return
		}
	} else {
		// 表单或其他：读取 host/type
		if err := r.ParseForm(); err == nil {
			if req.Domain == "" {
				req.Domain = r.FormValue("domain")
			}
			if req.Domain == "" {
				// 旧版参数名
				req.Domain = r.FormValue("host")
			}
			if req.Type == "" {
				req.Type = r.FormValue("type")
			}
		}
	}

	// 兼容清洗原始输入并验证
	req.Domain = validator.CleanDomainInput(req.Domain)
	if err := validator.ValidateDomain(req.Domain); err != nil {
		h.sendError(w, http.StatusBadRequest, err.Error())
		return
	}

	// 标准化域名
	domain := validator.NormalizeDomain(req.Domain)

	ctx := r.Context()

	// 如果没有指定类型，查询所有类型
	if req.Type == "" || strings.EqualFold(req.Type, "ALL") {
		// 先探测 API 可用性：查询 A 记录。API 不可用时返回错误
		// 查询时去除通配符前缀
		queryDomain := domain
		if after, ok := strings.CutPrefix(queryDomain, "*."); ok {
			queryDomain = after
		}
		if _, err := h.dnsResolver.Query(ctx, queryDomain, dns.TypeA); err != nil {
			h.logger.WithError(err).Error("DNS query unavailable")
			h.sendError(w, http.StatusBadGateway, "DNS 查询失败："+err.Error())
			return
		}

		result, err := h.dnsResolver.QueryAll(ctx, queryDomain)
		if err != nil {
			h.logger.WithError(err).Error("DNS query failed")
			h.sendError(w, http.StatusInternalServerError, "查询失败："+err.Error())
			return
		}
		// 判空：所有记录均为空则视为失败
		if isDNSQueryAllEmpty(result) {
			h.sendErrorDetailed(w, http.StatusNotFound, "未找到 DNS 记录", []map[string]interface{}{{
				"domain": validator.ToUnicode(req.Domain),
				"type":   "ALL",
			}})
			return
		}

		h.sendSuccess(w, map[string]interface{}{
			"display_domain": validator.ToUnicode(req.Domain),
			"dns_servers":    h.dnsServers,
			"result":         result,
		})
		return
	}

	// 查询特定类型
	recordType := dns.RecordType(req.Type)
	// 查询时去除通配符前缀
	queryDomain := domain
	if after, ok := strings.CutPrefix(queryDomain, "*."); ok {
		queryDomain = after
	}

	// 特殊处理CAA记录
	if recordType == dns.TypeCAA {
		records, err := h.dnsResolver.QueryCAA(ctx, queryDomain)
		if err != nil {
			h.logger.WithError(err).Error("CAA query failed")
			h.sendError(w, http.StatusInternalServerError, "查询失败："+err.Error())
			return
		}

		h.sendSuccess(w, map[string]interface{}{
			"domain":         queryDomain,
			"display_domain": validator.ToUnicode(req.Domain),
			"type":           "CAA",
			"records":        records,
			"dns_servers":    h.dnsServers,
		})
		return
	}

	// 查询其他类型
	records, err := h.dnsResolver.Query(ctx, queryDomain, recordType)
	if err != nil {
		h.logger.WithError(err).Error("DNS query failed")
		h.sendError(w, http.StatusInternalServerError, "查询失败："+err.Error())
		return
	}
	if len(records) == 0 {
		h.sendErrorDetailed(w, http.StatusNotFound, "未找到 DNS 记录", []map[string]interface{}{{
			"domain": validator.ToUnicode(req.Domain),
			"type":   string(recordType),
		}})
		return
	}

	h.sendSuccess(w, map[string]interface{}{
		"domain":         queryDomain,
		"display_domain": validator.ToUnicode(req.Domain),
		"type":           req.Type,
		"records":        records,
		"dns_servers":    h.dnsServers,
	})
}

// （已移除）DomainVerifyHandler：合并到统一的 IssueVerify 接口

// LinkVerifyHandler 链接验证处理器
func (h *Handlers) LinkVerifyHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		h.sendError(w, http.StatusMethodNotAllowed, "仅支持 POST 请求")
		return
	}

	// 限制请求体大小至 200KB
	r.Body = http.MaxBytesReader(w, r.Body, 200*1024)

	var req struct {
		URL           string `json:"url"`
		CheckProtocol bool   `json:"check_protocol"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.sendError(w, http.StatusBadRequest, "Invalid request format")
		return
	}

	if req.URL == "" {
		h.sendError(w, http.StatusBadRequest, "URL 不能为空")
		return
	}

	ctx := r.Context()

	// 自动适配 http:// https:// 与 // 开头
	url := strings.TrimSpace(req.URL)
	useBoth := req.CheckProtocol
	if strings.HasPrefix(url, "//") {
		useBoth = true
	} else if !strings.Contains(url, "://") {
		// 无协议显式，尝试双协议
		useBoth = true
	}

	if useBoth {
		result, err := h.linkVerifier.VerifyWithProtocols(ctx, url)
		if err != nil {
			h.logger.WithError(err).Error("Link verification failed")
			h.sendError(w, http.StatusInternalServerError, "验证失败："+err.Error())
			return
		}
		h.sendSuccess(w, result)
		return
	}

	result, err := h.linkVerifier.Verify(ctx, url)
	if err != nil {
		h.logger.WithError(err).Error("Link verification failed")
		h.sendError(w, http.StatusInternalServerError, "Verification failed: "+err.Error())
		return
	}
	h.sendSuccess(w, result)
}

// WhoisQueryHandler WHOIS查询处理器
func (h *Handlers) WhoisQueryHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		h.sendError(w, http.StatusMethodNotAllowed, "仅支持 POST 请求")
		return
	}

	// 限制请求体大小至 200KB
	r.Body = http.MaxBytesReader(w, r.Body, 200*1024)

	var req struct {
		Domain string `json:"domain"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.sendError(w, http.StatusBadRequest, "Invalid request format")
		return
	}

	// 清洗输入域名
	req.Domain = validator.CleanDomainInput(req.Domain)
	if req.Domain == "" {
		h.sendError(w, http.StatusBadRequest, "域名不能为空")
		return
	}

	// 验证域名格式（拒绝 IP 地址）
	if err := validator.ValidateDomain(req.Domain); err != nil {
		h.sendError(w, http.StatusBadRequest, err.Error())
		return
	}

	ctx := r.Context()
	// WHOIS 查询时去掉通配符前缀，以免查询失败
	lookupDomain := req.Domain
	if after, ok := strings.CutPrefix(lookupDomain, "*."); ok {
		lookupDomain = after
	}

	result, err := h.whoisClient.Query(ctx, lookupDomain)
	if err != nil {
		h.logger.WithError(err).Error("WHOIS query failed")
		h.sendError(w, http.StatusInternalServerError, "Query failed: "+err.Error())
		return
	}
	// 判空：若关键字段与原始数据均为空，视为失败
	if strings.TrimSpace(result.Registrar) == "" &&
		strings.TrimSpace(result.CreatedDate) == "" &&
		strings.TrimSpace(result.UpdatedDate) == "" &&
		strings.TrimSpace(result.ExpiryDate) == "" &&
		len(result.NameServers) == 0 &&
		len(result.Status) == 0 &&
		strings.TrimSpace(result.RawData) == "" {
		h.sendErrorDetailed(w, http.StatusNotFound, "未找到 WHOIS 信息", []map[string]string{{
			"domain": validator.ToUnicode(req.Domain),
		}})
		return
	}

	// 统一响应字段，并附带 display_domain（用于前端保留显示 *.）
	h.sendSuccess(w, map[string]interface{}{
		"domain":         result.Domain,
		"display_domain": validator.ToUnicode(req.Domain),
		"registrar":      result.Registrar,
		"created_date":   orUnknown(result.CreatedDate),
		"updated_date":   orUnknown(result.UpdatedDate),
		"expiry_date":    orUnknown(result.ExpiryDate),
		"name_servers":   result.NameServers,
		"status":         result.Status,     // 已在后端清洗
		"status_info":    result.StatusInfo, // EPP状态详细信息
		"dnssec":         result.DNSSEC,
		"raw":            result.RawData,
	})
}

// IssueVerifyBatchAPIHandler 签发验证（支持多域名）
func (h *Handlers) IssueVerifyBatchAPIHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		h.sendError(w, http.StatusMethodNotAllowed, "仅支持 POST 请求")
		return
	}

	// 限制请求体大小至 200KB
	r.Body = http.MaxBytesReader(w, r.Body, 200*1024)

	var req struct {
		Brand   string `json:"brand"`
		Domains string `json:"domains"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.sendError(w, http.StatusBadRequest, "Invalid request format")
		return
	}

	if strings.TrimSpace(req.Brand) == "" || strings.TrimSpace(req.Domains) == "" {
		h.sendError(w, http.StatusBadRequest, "品牌和域名不能为空")
		return
	}

	domains := parseDomainsText(req.Domains)
	if len(domains) == 0 {
		h.sendError(w, http.StatusBadRequest, "没有提供有效的域名")
		return
	}

	results := h.caaVerifier.VerifyMultiple(r.Context(), domains, req.Brand)

	// 包装带有显示字段的结果
	wrapped := make([]map[string]interface{}, 0, len(results))
	allValid := true
	for _, res := range results {
		if res == nil {
			continue
		}
		if !res.Valid {
			allValid = false
		}
		displayChain := make([]string, 0, len(res.CNAMEChain))
		for _, n := range res.CNAMEChain {
			displayChain = append(displayChain, validator.ToUnicode(n))
		}
		wrapped = append(wrapped, map[string]interface{}{
			"domain":              res.Domain,
			"display_domain":      validator.ToUnicode(res.Domain),
			"brand":               res.Brand,
			"valid":               res.Valid,
			"message":             res.Message,
			"caa_records":         res.CAARecords,
			"cname_chain":         res.CNAMEChain,
			"cname_chain_display": displayChain,
			"root_domain":         res.RootDomain,
			"root_checked":        res.RootChecked,
			"errors":              res.Errors,
			"dnssec":              res.DNSSEC, // DNSSEC 检测信息
		})
	}

	if allValid {
		h.sendSuccess(w, map[string]interface{}{
			"brand":       req.Brand,
			"domains":     domains,
			"results":     wrapped,
			"all_valid":   allValid,
			"dns_servers": h.dnsServers,
		})
		return
	}

	// 失败：统一按 code=0 返回，同时在 errors 中附带每个域名的详细结果
	// 同时选择 422 以表明语义上的校验未通过
	failed := 0
	for _, it := range wrapped {
		if v, ok := it["valid"].(bool); ok && !v {
			failed++
		}
	}
	msg := fmt.Sprintf("验证失败：%d/%d 域名未通过", failed, len(wrapped))
	// 为每个结果添加 DNS 服务器信息
	for _, result := range wrapped {
		result["dns_servers"] = h.dnsServers
	}
	h.sendErrorDetailed(w, http.StatusUnprocessableEntity, msg, wrapped)
}

// GetLinkHandler 获取链接内容处理器
func (h *Handlers) GetLinkHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		h.sendError(w, http.StatusMethodNotAllowed, "仅支持 POST 请求")
		return
	}

	// 限制请求体大小至 200KB
	r.Body = http.MaxBytesReader(w, r.Body, 200*1024)

	var req struct {
		URL string `json:"url"`
	}

	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.sendError(w, http.StatusBadRequest, "Invalid request format")
		return
	}

	if req.URL == "" {
		h.sendError(w, http.StatusBadRequest, "URL 不能为空")
		return
	}

	ctx := r.Context()
	result, err := h.linkVerifier.FetchContent(ctx, req.URL)
	if err != nil {
		h.logger.WithError(err).Error("Content fetch failed")
		h.sendError(w, http.StatusInternalServerError, "获取失败："+err.Error())
		return
	}

	h.sendSuccess(w, result)
}

// parseDomainsText 解析 domains 文本（支持逗号/中文逗号/换行分隔）
func parseDomainsText(raw string) []string {
	cleaned := strings.ToLower(strings.TrimSpace(raw))
	// 中文逗号统一为英文逗号；不再支持换行分割，按英文逗号拆分
	cleaned = strings.ReplaceAll(cleaned, "，", ",")
	// 按逗号拆分
	items := strings.Split(cleaned, ",")
	domains := make([]string, 0, len(items))
	// 清洗无效项（保留通配符前缀 *. 以支持通配域名）
	for _, d := range items {
		d = validator.CleanDomainInput(strings.TrimSpace(d))
		if d == "" {
			continue
		}
		// 简单校验：保留可能的域名或 IP（issue-verify 接口允许 IP 地址）
		domains = append(domains, d)
	}

	// 去重
	uniq := make(map[string]struct{})
	var out []string
	for _, d := range domains {
		if _, ok := uniq[d]; ok {
			continue
		}
		uniq[d] = struct{}{}
		out = append(out, d)
	}
	return out
}

// sendSuccess 发送成功响应（HTTP 200 + code=1）
func (h *Handlers) sendSuccess(w http.ResponseWriter, data interface{}) {
	h.sendJSON(w, http.StatusOK, Response{
		Code: 1,
		Data: data,
	})
}

// sendError 发送错误响应（HTTP 200 + code=0）
// 说明：按产品约定，失败也使用 HTTP 200，由 code=0 表示失败。
//
//	status 参数暂保留用于未来特殊情况（当前忽略）。
func (h *Handlers) sendError(w http.ResponseWriter, status int, message string) {
	_ = status
	h.sendJSON(w, http.StatusOK, Response{
		Code: 0,
		Msg:  message,
	})
}

// sendErrorDetailed 发送带 errors 的错误响应
// 说明：同上，失败统一 HTTP 200，由 code=0 标记失败。
func (h *Handlers) sendErrorDetailed(w http.ResponseWriter, status int, message string, errors interface{}) {
	_ = status
	h.sendJSON(w, http.StatusOK, Response{
		Code:   0,
		Msg:    message,
		Errors: errors,
	})
}

// sendJSON 发送JSON响应
func (h *Handlers) sendJSON(w http.ResponseWriter, status int, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	// 防止任何形式的缓存
	w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
	w.Header().Set("Pragma", "no-cache")
	w.Header().Set("Expires", "0")
	w.WriteHeader(status)

	if err := json.NewEncoder(w).Encode(data); err != nil {
		h.logger.WithError(err).Error("Failed to encode response")
	}
}

// ApplyCORS 应用CORS中间件
func ApplyCORS(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
		// 防止任何形式的缓存
		w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
		w.Header().Set("Pragma", "no-cache")
		w.Header().Set("Expires", "0")

		if r.Method == http.MethodOptions {
			w.WriteHeader(http.StatusOK)
			return
		}

		next(w, r)
	}
}

// orUnknown 简单空值替换为“未知”
func orUnknown(s string) string {
	if strings.TrimSpace(s) == "" {
		return "未知"
	}
	return s
}

// isDNSQueryAllEmpty 判断 ALL 查询是否无任何记录
func isDNSQueryAllEmpty(q *dns.QueryResult) bool {
	if q == nil {
		return true
	}
	return len(q.A) == 0 && len(q.AAAA) == 0 && len(q.CNAME) == 0 && len(q.MX) == 0 && len(q.TXT) == 0 && len(q.NS) == 0 && len(q.CAA) == 0
}
